﻿#ifndef _CRYPTOPP_AES_HELP_
#define _CRYPTOPP_AES_HELP_

#include <iostream>
#include <string>
#include <cryptopp/aes.h>      // 包含AES加密算法的头文件
#include <cryptopp/filters.h>  // 包含加解密过程中使用的filters头文件
#include <cryptopp/modes.h>    // 包含加解密过程中使用的modes头文件
#include <cryptopp/hex.h>      // 包含将二进制转换为十六进制的头文件
#include <cryptopp/sha.h>
#include <fstream>

// 都是 AES CBC 加密

// 使用SHA-256生成固定长度的密钥
inline std::string make_aes_hash_key(const std::string& input) {
    std::string hash;
    hash.resize(CryptoPP::SHA256::DIGESTSIZE); // SHA-256 哈希值的长度为32字节
    CryptoPP::SHA256().CalculateDigest(
        reinterpret_cast<CryptoPP::byte*>(const_cast<char*>(hash.data())), 
        reinterpret_cast<const CryptoPP::byte*>(input.c_str()),
        input.length());
    return hash;
}


inline bool resure_aes_key(std::string key) {
    size_t l = key.size();
    if (l != 16 && l != 24 && l != 32) {
        std::cerr << "AES key's length must be 16/24/32, but now key's length=" << l << std::endl;
        return false;
    }
    return true;
}


// AES加密
inline bool AES_encode(const std::string& str, const std::string& key, std::string& ciphertext) {
    if (resure_aes_key(key)) {
        try {
            CryptoPP::byte iv[CryptoPP::AES::BLOCKSIZE];
            memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);
            CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryption((CryptoPP::byte*)key.c_str(), key.length(), iv);
            CryptoPP::StringSink* Sink = new CryptoPP::StringSink(ciphertext);
            CryptoPP::StreamTransformationFilter* filter = new CryptoPP::StreamTransformationFilter(encryption, Sink);
            CryptoPP::StringSource s(str, true, filter);
        }
        //delete Sink, filter; //这里不释放才是对的
        catch (...) {
            ciphertext.clear();
            return false;
        }
    }
    return true;
}


// AES解密
inline bool AES_decode(const std::string& str, const std::string& key, std::string& decryptedtext) {
    if (resure_aes_key(key)) {
        try{
        CryptoPP::byte iv[CryptoPP::AES::BLOCKSIZE];
        memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);
        CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryption((CryptoPP::byte*)key.c_str(), key.length(), iv);
        CryptoPP::StringSink* Sink = new CryptoPP::StringSink(decryptedtext);
        CryptoPP::StreamTransformationFilter* filter = new CryptoPP::StreamTransformationFilter(decryption, Sink);
        CryptoPP::StringSource s(str, true, filter);
        //delete Sink, filter; //这里不释放才是对的
        }
        catch (...) {
            decryptedtext.clear();
            return false;
        }
    }
    return true;
}

// AES加密 (对密匙hash)
inline bool AES_encode_hashkey(const std::string& str, const std::string& key , std::string& output_str) {
    return AES_encode(str, make_aes_hash_key(key), output_str);
}

// AES解密 (对密匙hash)
inline bool AES_decode_hashkey(const std::string& str, const std::string& key, std::string& output_str) {
    return AES_decode(str, make_aes_hash_key(key), output_str);
}


// AES加密文件的第 m 到 n 个字符
inline bool AES_encode_file_part(const std::string& filename, int m, int n, const std::string& key) {
    if (m > n || m < 0) {
        std::cerr << "Invalid range: m should be less than or equal to n and non-negative." << std::endl;
        return false;
    }
    // 读取文件内容
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();
    // 检查范围是否有效
    if (n >= static_cast<int>(content.size())) {
        std::cerr << "Range out of bounds: n should be less than the file size." << std::endl;
        return false;
    }
    // 提取需要加密的部分
    std::string part_to_encrypt = content.substr(m, n - m + 1);
    // 加密部分
    std::string encrypted_part;
    if (!AES_encode(part_to_encrypt, key, encrypted_part)) {
        std::cerr << "AES failed to encode" << std::endl;
        return false;
    }
    // 将加密部分重新写回文件
    std::string new_content = content.substr(0, m) + encrypted_part + content.substr(n + 1);
    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    outfile.write(new_content.c_str(), new_content.size());
    outfile.close();
    return true;
}

// AES加密整个文件
inline bool AES_encode_file(const std::string& filename, const std::string& key) {
    // 读取文件内容
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();
    // 加密整个文件内容
    std::string encrypted_content;
    if (!AES_encode(content, key, encrypted_content)) {
        std::cerr << "AES failed to encode" << std::endl;
        return false;
    }
    // 将加密后的内容写回文件
    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    outfile.write(encrypted_content.c_str(), encrypted_content.size());
    outfile.close();
    return true;
}


// AES解密文件的第 m 到 n 个字符
inline bool AES_decode_file_part(const std::string& filename, int m, int n, const std::string& key) {
    if (m > n || m < 0) {
        std::cerr << "Invalid range: m should be less than or equal to n and non-negative." << std::endl;
        return false;
    }
    // 读取文件内容
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();
    // 检查范围是否有效
    if (n >= static_cast<int>(content.size())) {
        std::cerr << "Range out of bounds: n should be less than the file size." << std::endl;
        return false;
    }
    // 提取需要加密的部分
    std::string part_to_encrypt = content.substr(m, n - m + 1);
    // 加密部分
    std::string encrypted_part;
    if (!AES_decode(part_to_encrypt, key, encrypted_part)) {
        std::cerr << "AES failed to decode" << std::endl;
        return false;
    }
    // 将加密部分重新写回文件
    std::string new_content = content.substr(0, m) + encrypted_part + content.substr(n + 1);
    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    outfile.write(new_content.c_str(), new_content.size());
    outfile.close();
    return true;
}

// AES解密整个文件
inline bool AES_decode_file(const std::string& filename, const std::string& key) {
    // 读取文件内容
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();
    std::string encrypted_content;
    if (!AES_decode(content, key, encrypted_content)) {
        std::cerr << "AES failed to decode" << std::endl;
        return false;
    }
    // 将加密后的内容写回文件
    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile) {
        std::cerr << "cannot open this file:" << filename << std::endl;
        return false;
    }
    outfile.write(encrypted_content.c_str(), encrypted_content.size());
    outfile.close();
    return true;
}


#endif // !_CRYPTOPP_AES_HELP_